/*
 * @Description:
 * @Author: Junhuang
 * @Date: 2022-02-08 16:21:23
 * @LastEditTime: 2022-05-29 10:25:56
 * @LastEditors: Junhuang
 * @Reference:
 */
'use strict';

const Controller = require('egg').Controller;


class UserController extends Controller {
  // 注册
  async reg() {
    const { ctx, app } = this;
    // 参数验证
    ctx.validate({
      username: { type: 'string', required: true, range: { min: 5, max: 20 }, desc: '用户名' },
      password: { type: 'string', required: true, desc: '密码' },
      repassword: { type: 'string', required: true, desc: '确认密码' },
    }, {
      equals: [[ 'password', 'repassword' ]],
    });

    const { username, password } = ctx.request.body;
    console.log('ctx.request.body', ctx.request.body);
    // 用户名是否存在
    const auser = await app.model.User.findOne({
      where: {
        username,
      },
    });

    if (auser) {
      ctx.throw(400, '用户名已存在');
    }

    // 创建用户
    let user = await app.model.User.create({
      username,
      password,
    });

    if (!user) {
      ctx.throw(400, '用户创建失败');
    }

    // 特别注意，由于通过model返回对user对象，并非单纯的user对象，还含有许多其他内容，因此在进行token使用时建议进行转换
    user = JSON.parse(JSON.stringify(user));
    delete user.password;

    ctx.apiSuccesss(user);
  }

  // 登录
  async login() {
    const { ctx, app, service } = this;
    // 参数验证
    ctx.validate({
      username: { type: 'string', required: true, desc: '用户名' },
      password: { type: 'string', required: true, desc: '密码' },
    });

    // 验证用户是否存在
    const { username, password } = ctx.request.body;
    // 用户名是否存在
    let user = await app.model.User.findOne({
      where: {
        username,
      },
    });
    if (!user) {
      ctx.throw(400, '用户不存在或被禁用');
    }

    // 验证密码是否正确
    const cres = service.user.checkPassword(password, user.password);
    if (!cres) {
      ctx.throw(400, '密码不匹配或错误');
    }

    // 特别注意，由于通过model返回对user对象，并非单纯的user对象，还含有许多其他内容，因此在进行token使用时建议进行转换
    user = JSON.parse(JSON.stringify(user));

    // 生成token
    const token = ctx.getToken(user);
    user.token = token;
    delete user.password;

    // 加入缓存
    if (!await this.service.cache.set('user_' + user.id, token)) {
      ctx.throw(400, '登录失败-redis缓存错误');
    }
    ctx.apiSuccesss(user);
  }

  // 退出登录
  async logout() {
    const { ctx, service } = this;
    // 拿到当前用户id
    const c_user_id = ctx.authUser.id;
    // 移除redis中当前用户信息
    if (!await service.cache.remove('user_' + c_user_id)) {
      ctx.throw(400, '退出登录失败-redis异常');
    }
    ctx.apiSuccesss('退出成功');
  }

  // 修改密码
  async password() {
    const { ctx, app, service } = this;
    const { password, newpassword, repassword } = ctx.request.body;
    // 参数验证
    ctx.validate({
      password: { type: 'string', required: true, desc: '原密码' },
      newpassword: { type: 'string', required: true, range: { min: 6, max: 20 }, desc: '新密码' },
      repassword: { type: 'string', required: true, range: { min: 6, max: 20 }, desc: '确认密码' },
    }, {
      equals: [[ 'newpassword', 'repassword' ]],
    });

    if (repassword !== newpassword) {
      return ctx.apiFail('新密码与确认密码不相同');
    }

    if (password === newpassword) {
      return ctx.apiFail('新密码与原密码不能相同');
    }

    // 验证用户是否存在
    const user = await app.model.User.findByPk(ctx.authUser.id);
    if (!user) {
      return ctx.apiFail('当前用户不存在');
    }

    // 验证密码是否正确
    const cres = service.user.checkPassword(password, user.password);
    if (!cres) {
      return ctx.apiFail('原密码不匹配或错误');
    }

    user.password = newpassword;
    await user.save();
    return ctx.apiSuccesss('密码修改成功');
  }

  // 修改用户非核心信息：
  async info() {
    const { ctx, app } = this;
    const { nickname, email, avatar, phone, sex, description } = ctx.request.body;

    // 验证用户是否存在
    const user = await app.model.User.findByPk(ctx.authUser.id);
    if (!user) {
      return ctx.apiFail('当前用户不存在');
    }

    if (email) {
      user.email = email;
    }

    if (avatar) {
      user.avatar = avatar;
    }

    if (nickname) {
      user.nickname = nickname;
    }

    if (phone) {
      user.phone = phone;
    }

    if (sex) {
      user.sex = sex;
    }

    if (description) {
      user.description = description;
    }

    await user.save();
    return ctx.apiSuccesss('修改成功');
  }

  // 关注
  async follow() {
    const { ctx, app, service } = this;
    const user_id = ctx.authUser.id;

    ctx.validate({
      follow_user_id: {
        type: 'int',
        required: true,
        desc: '被关注的用户id',
      },
    });


    const { follow_user_id } = ctx.request.body;

    // 不能专注自己
    if (follow_user_id === user_id) {
      return ctx.apiFail('不能关注自己');
    }

    // 判断被关注的用户是否存在
    // 【特别注意】关于service的用法
    if (!(await service.user.exist(follow_user_id))) {
      return ctx.apiFail('关注的用户不存在');
    }

    let follow = await app.model.Follow.findOne({
      where: {
        user_id,
        follow_user_id,
      },
    });

    if (follow) {
      // 说明已经关注过
      return ctx.apiFail('已经关注过了');
    }

    follow = await app.model.Follow.create({
      user_id,
      follow_user_id,
    });
    return ctx.apiSuccesss('关注成功');
  }

  // 取消关注
  async unfollow() {
    const { ctx, app, service } = this;
    const user_id = ctx.authUser.id;
    const { follow_user_id } = ctx.request.body;

    ctx.validate({
      follow_user_id: {
        type: 'int',
        required: true,
        desc: '被关注的用户id',
      },
    });

    // 不能取消或专注自己
    if (follow_user_id === user_id) {
      return ctx.apiFail('不能取消关注自己');
    }

    // 判断被关注的用户是否存在
    // 【特别注意】关于service的用法
    if (!(await service.user.exist(follow_user_id))) {
      return ctx.apiFail('取消关注的用户不存在');
    }

    const follow = await app.model.Follow.findOne({
      where: {
        user_id,
        follow_user_id,
      },
    });

    if (!follow) {
      return ctx.apiFail('您没有关注过该用户，无法取消关注');
    }

    follow.destroy();
    return ctx.apiSuccesss('取消关注成功');

  }

  // 删除指定用户的粉丝
  async dropFan() {
    const { ctx, app } = this;
    const follow_user_id = ctx.authUser.id;
    const { fan_user_id } = ctx.request.body;
    ctx.validate({
      fan_user_id: {
        type: 'int',
        required: true,
        desc: '要被删除的粉丝id',
      },
    });

    const fan = await app.model.Follow.findOne({
      where: {
        user_id: fan_user_id, // 发起关注的人（也就是粉丝）
        follow_user_id, // 被关注的人
      },
    });

    if (!fan) {
      return ctx.apiFail('你没有该粉丝，无法删除');
    }

    fan.destroy();
    return ctx.apiSuccesss('删除该粉丝成功');

  }

  // 我关注的人的列表-分页
  // /user/follows/:page
  // 访问地址：http://127.0.0.1:7001/user/follows/1?limit=10
  async follows() {
    const { ctx, app } = this;
    const user_id = ctx.authUser.id;
    let rows = await ctx.page(app.model.Follow, {
      user_id,
    }, {
      include: [{
        // 【特别注意】由于follow实体有两个id(user_id,follow_user_id)都指向user表
        //  而且在实体类中，我们分别建立了‘send_user’，‘follow_user’的别名
        //  此处我们是要得到所有我关注的用户，也就是follow_user，所以这里include时要使用follow_user,否则将会报错
        model: app.model.User,
        as: 'follow_user',
        // 【特别注意】关于此处列重新命名的方式
        attributes: [[ 'id', 'user_id' ], 'username', 'nickname', 'avatar' ],
      }],
    });
    rows = rows.map(item => {
      return item.follow_user;
    });
    return ctx.apiSuccesss(rows);
  }

  // 我的粉丝列表-分页
  async fans() {
    const { ctx, app } = this;
    const follow_user_id = ctx.authUser.id;
    let rows = await ctx.page(app.model.Follow, {
      follow_user_id,
    }, {
      include: [{
        // 【特别注意】由于follow实体有两个id(user_id,follow_user_id)都指向user表
        //  而且在实体类中，我们分别建立了‘send_user’，‘follow_user’的别名
        //  此处我们的粉丝，也就是专注我的用户，也就是send_user，所以这里include时要使用send_user,否则将会报错
        model: app.model.User,
        as: 'send_user',
        // 【特别注意】关于此处列重新命名的方式
        attributes: [[ 'id', 'user_id' ], 'username', 'nickname', 'avatar' ],
      }],
    });
    rows = rows.map(item => {
      return item.send_user;
    });
    return ctx.apiSuccesss(rows);
  }

  // 获取当前用户相关统计信息
  async statistics() {
    const { ctx, service } = this;
    const user_id = ctx.authUser.id;

    const followCount = await service.user.getFollowCount(user_id);
    const fanCount = await service.user.getFanCount(user_id);
    const videoCount = await service.user.getVideoCount(user_id);
    const favaCount = await service.fava.getFavaCount(user_id);

    ctx.apiSuccesss({
      user_id,
      followCount,
      fanCount,
      videoCount,
      favaCount,
    });
  }

  // 获取用户相关信息(不需要登录即可访问)
  // 访问地址：http://127.0.0.1:7001/user/user_info/1?user_id=1
  async user_info() {
    const { ctx, service } = this;
    // let currentUser = ctx.authUser;
    ctx.validate({
      user_id: {
        required: true,
        desc: '用户id',
        type: 'int',
      },
    });
    const user_id = ctx.query.user_id;
    const res = await service.user.getUserInfo(user_id);
    let fansCount = 0;
    let followCount = 0;
    let videoCount = 0;
    if (res) {
      fansCount = await service.user.getFanCount(user_id);
      videoCount = await service.user.getVideoCount(user_id);
      followCount = await service.user.getFollowCount(user_id);
    }

    // // 指定的用户是否被当前用户（currentUser）关注
    // let followed = false;
    // if (currentUser) {
    //   followed = await service.user.isFollow(currentUser.id, user_id);
    // }
    return ctx.apiSuccesss({
      user: res,
      fansCount,
      videoCount,
      followCount,
    });
  }

  // 判断当前用户是否关注了指定用户
  // 访问地址：http://127.0.0.1:7001/user/followed?user_id=1
  async isFollowed() {
    const { ctx, service } = this;
    const currentUser = ctx.authUser;
    ctx.validate({
      user_id: {
        required: true,
        desc: '用户id',
        type: 'int',
      },
    });
    const user_id = ctx.query.user_id;
    // 指定的用户是否被当前用户（currentUser）关注
    let followed = false;
    if (currentUser) {
      followed = await service.user.isFollow(currentUser.id, user_id);
    }
    return ctx.apiSuccesss({
      followed,
    });
  }

  // 查询用户列表
  async list() {
    const { ctx, app } = this;
    const where = {};

    // 组织查询条件
    // id用全等
    if (ctx.query.id && ctx.query.id.length > 0) {
      where.id = ctx.query.id;
    }
    // stauts全等
    if (ctx.query.status) {
      where.status = parseInt(ctx.query.status);
    }
    // username用like
    const Op = app.Sequelize.Op;
    if (ctx.query.username && ctx.query.username.length > 0) {
      where.username = {
        [Op.like]: '%' + ctx.query.username + '%',
      };
    }

    // name用like
    if (ctx.query.nickname && ctx.query.nickname.length > 0) {
      where.nickname = {
        [Op.like]: '%' + ctx.query.nickname + '%',
      };
    }
    // console.log('where=', where);

    const options = {};
    // 组织排序
    if (ctx.query.sort && ctx.query.sort.length > 0) {
      const direction = ctx.query.sort.slice(0, 1) === '+' ? 'ASC' : 'DESC';
      const sortColumn = ctx.query.sort.slice(1);
      options.order = [[ sortColumn, direction ]];
    }
    // console.log('options=', options);

    const res = await ctx.pageAndCount(app.model.User.scope('excludedPassword'), where, options);
    // const items = [];
    ctx.apiSuccesss({
      total: res.count,
      items: res.rows,
    });
  }

  // 更改用户状态
  // '/user/:id/status'
  async changeStatus() {
    const { ctx, app } = this;
    const { status } = ctx.request.body;
    ctx.validate({
      id: {
        required: true,
        type: 'int',
        desc: 'id',
      },
      status: {
        required: true,
        type: 'int',
        desc: 'status',
      },
    });

    const user = await app.model.User.scope('excludedPassword').findOne({
      where: {
        id: ctx.params.id,
      },
    });

    if (!user) {
      return ctx.throw(404, '该用户不存在');
    }

    if (user.status === status) {
      return ctx.throw('该用户状态与要变化的状态一致，不用变化！');
    }

    user.status = status;
    user.save();

    const res = JSON.parse(JSON.stringify(user));
    return ctx.apiSuccesss(res);
  }
}

module.exports = UserController;
